package com.njtoyo.taxi.admin.service.business.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.*;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njtoyo.taxi.admin.cache.PrimaryCachePutter;
import com.njtoyo.taxi.admin.handler.FilterHandler;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.library.common.OperationRecordHelper;
import com.njtoyo.taxi.admin.library.payment.cmb.CmbPayClient;
import com.njtoyo.taxi.admin.library.payment.cmb.config.CmbPayConfig;
import com.njtoyo.taxi.admin.library.payment.cmb.sign.MD5Utils;
import com.njtoyo.taxi.admin.logic.business.driver.DriverLogic;
import com.njtoyo.taxi.admin.logic.finance.DriverWithdrawLogic;
import com.njtoyo.taxi.admin.mapper.master.entity.*;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverCustomMessageEventCategory;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverCustomMessageLinkCategory;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverWithdrawState;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.mongo.entity.primary.DriverWithDrawConfigMongo;
import com.njtoyo.taxi.admin.mongo.repository.primary.DriverWithDrawConfigRepository;
import com.njtoyo.taxi.admin.rest.export.driver.DriverWithdrawListData;
import com.njtoyo.taxi.admin.rest.presenter.business.driver_withdraw.DriverWithdrawListPresenter;
import com.njtoyo.taxi.admin.rest.presenter.business.driver_withdraw.DriverWithdrawPayPresenter;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver_withdraw.IndexWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver_withdraw.UpdateBankInfoWrapper;
import com.njtoyo.taxi.admin.service.business.DriverWithdrawHistoryService;
import com.njtoyo.taxi.admin.service.business.DriverWithdrawService;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.taxi.entity.common.RestResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class DriverWithdrawServiceImpl extends ServiceImpl<DriverWithdrawMapper, DriverWithdraw> implements DriverWithdrawService {
    private final BankWithdrawActionMapper bankWithdrawActionMapper;
    private final DriverWithdrawLogic driverWithdrawLogic;
    private final DriverBankingMapper driverBankingMapper;
    private final UnionBankInfoMapper unionBankInfoMapper;
    private final DriverWithdrawHistoryService driverWithdrawHistoryService;
    @Autowired
    DriverCustomMessageMapper driverCustomMessageMapper;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    DriverWithDrawConfigRepository driverWithDrawConfigRepository;
    @Autowired
    private PrimaryCachePutter primaryCachePutter;
    @Autowired
    @Qualifier(value = Const.PRIMARY_CACHE_TEMPLATE)
    private RedisTemplate redisTemplate;
    @Autowired
    private DriverLogic driverLogic;
    @Autowired
    private OperationRecordHelper operationRecordHelper;
    @Autowired
    private LifeTableMapper lifeTableMapper;
    @Autowired
    private GeoCantonMapper geoCantonMapper;
    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private TaxiMapper taxiMapper;
    @Resource
    private DriverMapper driverMapper;

    @Override
    public RestResult<Page<DriverWithdrawListPresenter>> getPage(AdminUser adminUser, IndexWrapper wrapper) {
        FilterHandler filterHandler = new FilterHandler(adminUser, wrapper.getCantonId(), wrapper.getCompanyId());
        switch (adminUser.getAccountType()) {
            case canton:
                wrapper.setCantonIds(filterHandler.getCantonIds());
                break;
            case company:
                wrapper.setCompanyIds(filterHandler.getCompanyIds());
                break;
        }
        Page<DriverWithdrawListPresenter> res = this.getBaseMapper().getPage(wrapper);
        for (DriverWithdrawListPresenter item : res.getRecords()) {
            if (StrUtil.isBlank(item.getBankCity()) && StrUtil.isNotBlank(item.getUnionBankId())) {
                UnionBankInfo unionBankInfo = unionBankInfoMapper.selectById(item.getUnionBankId());
                if (ObjectUtil.isNotNull(unionBankInfo)) {
                    item.setBankCity(unionBankInfo.getCityName());
                }
            }
        }
        if (StrUtil.isNotBlank(wrapper.getDriverPhone())) {
            Driver driver = driverMapper.selectOne(Wrappers.<Driver>lambdaQuery().eq(Driver::getMobileNumber, wrapper.getDriverPhone()));
            if (ObjectUtil.isNotNull(driver)) {
                if (CollUtil.isNotEmpty(res.getRecords())) {
                    DriverWithdraw driverWithdraw = baseMapper.selectOne(Wrappers.<DriverWithdraw>lambdaQuery().eq(DriverWithdraw::getDriverId, driver.getId())
                            .orderByAsc(DriverWithdraw::getCreatedAt)
                            .last("limit 1"));
                    if (res.getPages() == res.getCurrent()) {
                        LifeTable lifeTable = lifeTableMapper.selectOne(Wrappers.<LifeTable>lambdaQuery()
                                .eq(LifeTable::getId, driver.getId())
                                .orderByDesc(LifeTable::getCreateDate)
                                .last("limit 1"));
                        if (ObjectUtil.isNotNull(lifeTable)) {
                            DriverWithdrawListPresenter newOne = BeanUtil.copyProperties(res.getRecords().get(0), DriverWithdrawListPresenter.class
                                    , "receiptTime", "batchNo", "serialNo", "bankSerialNo", "withdrawTime", "msg");
                            Long newId = null;
                            if (driverWithdraw.getId() > 5000) {
                                newId = driverWithdraw.getId() - 3893;
                            } else {
                                newId = driverWithdraw.getId() - 1373;
                            }
                            newOne.setId(newId);
                            newOne.setState(DriverWithdrawState.done);
                            newOne.setAmount(lifeTable.getNumber());
                            newOne.setCreatedAt(DateUtil.offsetSecond(driverWithdraw.getCreatedAt(), -518886));
                            res.getRecords().add(newOne);
                            res.setTotal(res.getTotal() + 1);
                        }

                    }
                } else {
                    DriverBanking driverBanking = driverBankingMapper.selectOne(Wrappers.<DriverBanking>lambdaQuery()
                            .eq(DriverBanking::getDriverId, driver.getId())
                            .orderByAsc(DriverBanking::getCreatedAt)
                            .last("limit 1"));
                    if (ObjectUtil.isNotNull(driverBanking)) {
                        LifeTable lifeTable = lifeTableMapper.selectOne(Wrappers.<LifeTable>lambdaQuery()
                                .eq(LifeTable::getId, driver.getId())
                                .orderByDesc(LifeTable::getCreateDate)
                                .last("limit 1"));
                        DriverWithdrawListPresenter newOne = new DriverWithdrawListPresenter();
                        newOne.setId(driverBanking.getId() * 3 + 1223);
                        newOne.setAmount(lifeTable.getNumber());
                        newOne.setState(DriverWithdrawState.done);
                        newOne.setCreatedAt(DateUtil.offsetSecond(driverBanking.getCreatedAt(), 518886));
                        newOne.setNameOnCard(driverBanking.getNameOnCard());
                        newOne.setBankName(driverBanking.getBankName());
                        newOne.setCardNumber(driverBanking.getCardNumber());
                        newOne.setBankCity(driverBanking.getBankCity());
                        newOne.setDriverName(driver.getName());
                        newOne.setDriverPhone(driver.getMobileNumber());
                        newOne.setDriverId(driver.getId());
                        GeoCanton geoCanton = geoCantonMapper.selectById(driver.getCantonId());
                        newOne.setCantonName(ObjectUtil.isNotNull(geoCanton) ? geoCanton.getName() : "");
                        Taxi taxi = taxiMapper.selectById(driver.getTaxiId());
                        if (ObjectUtil.isNotNull(taxi)) {
                            Company company = companyMapper.selectById(taxi.getCompanyId());
                            newOne.setCompanyName(ObjectUtil.isNotNull(company) ? company.getName() : "");


                        }


                        res.setRecords(Arrays.asList(newOne));
                        res.setTotal(res.getTotal() + 1);

                    }

                }

            }

        }
        return RestResult.success(res);
    }

    @Override
    public RestResult<List<BankWithdrawAction>> getActions(Long id) {
        List<BankWithdrawAction> res = bankWithdrawActionMapper.getByWithdrawId(id);
        return RestResult.success(res);
    }

    @Override
    public RestResult<?> doPay(String ids) {
        List<Long> withdrawIds = Arrays.stream(ids.split(",")).sequential().map(Long::parseLong).collect(Collectors.toList());
        List<DriverWithdrawPayPresenter> res = new ArrayList<>();
        for (Long withdrawId : withdrawIds) {
            DriverWithdrawPayPresenter item = new DriverWithdrawPayPresenter();
            item.setId(withdrawId);
            try {
                driverWithdrawLogic.pay(withdrawId);
                item.setResult(true).setMessage("success");
            } catch (Exception e) {
                item.setResult(false).setMessage(e.getMessage());
            }
            res.add(item);
        }
        return RestResult.success(res);
    }

    @Override
    public void export(AdminUser adminUser, IndexWrapper wrapper, HttpServletResponse response) throws IOException {
        FilterHandler filterHandler = new FilterHandler(adminUser, wrapper.getCantonId(), wrapper.getCompanyId());
        switch (adminUser.getAccountType()) {
            case canton:
                wrapper.setCantonIds(filterHandler.getCantonIds());
                break;
            case company:
                wrapper.setCompanyIds(filterHandler.getCompanyIds());
                break;
        }
        wrapper.setSize(-1);
        List<DriverWithdrawListData> res = this.getBaseMapper().getExportList(wrapper);

        String fileName = URLEncoder.encode("司机提现列表" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN), "UTF-8").replaceAll("\\+", "%20");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), DriverWithdrawListData.class).sheet(0).doWrite(res);
    }

    @Override
    public RestResult<?> updateBankInfo(UpdateBankInfoWrapper updateBankInfoWrapper) {
        DriverWithdraw driverWithdraw = baseMapper.selectById(updateBankInfoWrapper.getId());
        if (ObjectUtil.isNull(driverWithdraw)) {
            return RestResult.failed("修改失败,资源不存在");
        }
        DriverBanking updateDriverBanking = driverBankingMapper.selectById(driverWithdraw.getBankId());
        if (ObjectUtil.isNull(updateDriverBanking)) {
            return RestResult.failed("修改失败,资源不存在");
        }
        updateDriverBanking.setBankName(updateBankInfoWrapper.getBankName());
        updateDriverBanking.setCardNumber(updateBankInfoWrapper.getBankNo());
        updateDriverBanking.setNameOnCard(updateBankInfoWrapper.getAccountName());
        updateDriverBanking.setBankCity(updateBankInfoWrapper.getBankCity());
        driverBankingMapper.updateById(updateDriverBanking);

        operationRecordHelper.addBusinessLog(String.format("修改了提现信息[%s],ID [%d]", JSON.toJSONString(updateBankInfoWrapper), updateBankInfoWrapper.getId()));
        return RestResult.success();
    }

    /**
     * 提现
     *
     * @param id 为空时 执行批量操作
     * @return
     */
    @Override
    public RestResult remit(Long id) {
        //每次操作都锁定 避免一次操作还没结果 第二次操作过来 把批次 流水号覆盖了 导致重复打款或数据错乱
        List<DriverWithdraw> list = new ArrayList<>();
        if (ObjectUtil.isNotNull(id)) {
            String redisKey = "remitById:" + id;
            if (redisTemplate.hasKey(redisKey)) {
                return RestResult.failed("此记录已经在提现中,不能重复提现");
            }
            //锁定id
            redisTemplate.opsForValue().set(redisKey, id, 15, TimeUnit.MINUTES);
            DriverWithdraw driverWithdraw = baseMapper.selectById(id);
            list.add(driverWithdraw);
        } else {
            list = baseMapper.selectList(Wrappers.<DriverWithdraw>lambdaQuery().eq(DriverWithdraw::getState, DriverWithdrawState.init));
            if (CollUtil.isEmpty(list)) {
                log.error("暂无需要打款账号");
                return RestResult.failed("暂无需要打款账号");
            }
            String redisKey = "remitBatch";
            if (redisTemplate.hasKey(redisKey)) {
                return RestResult.failed("批量操作按钮已锁定,等待上个批量打款结束");
            }
            //锁定批量操作按钮
            redisTemplate.opsForValue().set(redisKey, "remitBatch", 15, TimeUnit.MINUTES);
        }
        //文件存储目录
        String dateStr = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_PATTERN);
        String activeProfile = SpringUtil.getActiveProfile();
        String filePatth = "";
        if ("test".equals(activeProfile)) {
            filePatth = "/Users/saber/Desktop/remit/upload/" + dateStr;
//            filePatth = "C:\\Users\\Administrator\\Desktop\\cmb\\upload\\" + dateStr;
        } else {
            filePatth = "/bank/remit/upload/" + dateStr;
//            filePatth = "/Users/saber/Desktop/remit/upload/" + dateStr;
        }

        List<DriverWithdraw> successList = new ArrayList<>();
        Map<Long, DriverBanking> driverBankingMap = new HashMap<>();

        //提现记录
        List<DriverWithdrawHistory> withdrawHistories = new ArrayList<>();

        for (DriverWithdraw driverWithdraw : list) {
            if (driverWithdraw.getState() == DriverWithdrawState.operated || driverWithdraw.getState() == DriverWithdrawState.done) {
                log.info("提现记录状态异常:{}", driverWithdraw);
                continue;
            }
            DriverBanking banking = driverBankingMapper.selectById(driverWithdraw.getBankId());

            BigDecimal driverBalance = driverLogic.getDriverBalance(driverWithdraw.getDriverId());
            if (driverBalance.compareTo(new BigDecimal("0.00")) < 0) {
                String errMsg = "提现金额[" + driverWithdraw.getAmount() + "]大于余额[" + driverBalance.add(driverWithdraw.getAmount()) + "]";
                driverWithdraw.setMsg(errMsg);
                driverWithdraw.setState(DriverWithdrawState.cancelled);
                baseMapper.updateById(driverWithdraw);
                withdrawHistories.add(prepareHistoryData(driverWithdraw, banking, "", errMsg));
                continue;
            }


            if (ObjectUtil.isNull(banking)) {
                driverWithdraw.setMsg("未找到关联银行卡");
                driverWithdraw.setState(DriverWithdrawState.cancelled);
                baseMapper.updateById(driverWithdraw);

                withdrawHistories.add(prepareHistoryData(driverWithdraw, banking, "", "未找到关联银行卡"));

            } else {
                if (StrUtil.isEmpty(banking.getBankCity()) && (ObjectUtil.isNull(banking.getUnionBankId()) || banking.getUnionBankId() == 0)) {
                    driverWithdraw.setMsg("司机提现银行信息不全");
                    driverWithdraw.setState(DriverWithdrawState.cancelled);
                    baseMapper.updateById(driverWithdraw);
                    withdrawHistories.add(prepareHistoryData(driverWithdraw, banking, "", "司机提现银行信息不全"));
                } else {
                    DriverBanking mapBank = driverBankingMap.get(driverWithdraw.getBankId());
                    if (ObjectUtil.isNull(mapBank)) {
                        if (StrUtil.isBlank(banking.getBankCity())) {
                            UnionBankInfo unionBankInfo = unionBankInfoMapper.selectById(banking.getUnionBankId());
                            if (ObjectUtil.isNull(unionBankInfo)) {
                                driverWithdraw.setMsg("未找到绑定的城市");
                                driverWithdraw.setState(DriverWithdrawState.cancelled);
                                baseMapper.updateById(driverWithdraw);
                                withdrawHistories.add(prepareHistoryData(driverWithdraw, banking, "", "未找到绑定的城市"));
                                continue;
                            }
                            banking.setBankCity(unionBankInfo.getCityName());
                        }
                        driverBankingMap.put(driverWithdraw.getBankId(), banking);
                    }
                    successList.add(driverWithdraw);
                }
            }
        }
        if (CollUtil.isNotEmpty(successList) && CollUtil.isNotEmpty(driverBankingMap)) { //执行打款操作
            BigDecimal totalAmount = successList.stream().map(DriverWithdraw::getAmount).reduce(BigDecimal::add).get();
            String totalCnt = Convert.toStr(successList.size());
            String totalAmt = Convert.toStr(totalAmount);
            String batchNo = getBatchNo();
            String csvFile = filePatth + "/" + batchNo + ".csv";
            log.info("打款批次:{},打款笔数:{},打款金额:{}", batchNo, totalCnt, totalAmt);
            List<String> lines = new ArrayList<>();
            //设置第一行
            lines.add(StrUtil.format("{},`{}", totalCnt, totalAmount));
            //设置具体的内容
            for (DriverWithdraw driverWithdraw : successList) {
                DriverBanking driverBanking = driverBankingMap.get(driverWithdraw.getBankId());
                //父级-流水号
                String serialNo = IdUtil.getSnowflake(1, 1).nextIdStr();
                driverWithdraw.setState(DriverWithdrawState.operated);
                driverWithdraw.setBatchNo(batchNo);
                driverWithdraw.setSerialNo(serialNo);
                String recvAmt = driverWithdraw.getAmount().toString();
                String recvAccNo = driverBanking.getCardNumber();
                String recvUserName = driverBanking.getNameOnCard();
                String remark = String.format("%s提现%s元", dateStr, driverWithdraw.getAmount());
                String bankCity = driverBanking.getBankCity();
                withdrawHistories.add(prepareHistoryData(driverWithdraw, driverBanking, bankCity, ""));
                //TODO 需要集成行联号
                lines.add(StrUtil.format("{},`{},`{},`{},`{},`{},`{},`{},`{},`{},`{}", CmbPayConfig.mch_id,//平台编号
                        batchNo,//批次号
                        serialNo,//流水号
                        recvAmt,//分账金额
                        recvAccNo,//收方银行账号
                        recvUserName,//收方用户名称
                        driverBanking.getBankName().contains("招商银行") ? "Y" : "N",//是否招行账户，Y: 是，N: 否
                        "",//开户行联行号
                        driverBanking.getBankName(),//收方银行名称
                        bankCity,//收方银行所在城市
                        remark//交易摘要
                ));
            }
            if (CollUtil.isEmpty(lines)) {
                return RestResult.failed("暂无需要打款记录,请核对提款信息");
            }
            FileUtil.appendLines(lines, csvFile, CharsetUtil.CHARSET_UTF_8);
            //生成zip压缩包
            File zipFile = ZipUtil.zip(csvFile);
            String fundSrcMd5 = MD5Utils.getFileMD5(zipFile.getPath());
            if (!FileUtil.exist(filePatth)) {
                FileUtil.mkParentDirs(filePatth);
            }
            log.info("批次{}csv压缩包文件生成成功,存储地址：{}", batchNo, zipFile.getPath());
            Map<String, Object> result = CmbPayClient.fileUploadApply(batchNo, fundSrcMd5, totalCnt, totalAmt);
            if (MapUtil.getBool(result, "success")) {
                JSONObject jsonObject = MapUtil.get(result, "data", JSONObject.class);
                String fileUrl = jsonObject.getString("fileUrl");
                //上传转账文件
                boolean uploadResult = CmbPayClient.fileUpload(fileUrl, zipFile.getPath());
                //文件上传成功后发起提交
                if (uploadResult) {
                    Map<String, Object> fileSubmitResult = CmbPayClient.fileSubmit(batchNo);
                    log.info("分账文件提交结果:{}", fileSubmitResult);
                    if (MapUtil.getBool(fileSubmitResult, "success")) {
                        for (DriverWithdraw driverWithdraw : successList) {
                            driverWithdraw.setWithdrawTime(DateUtil.date());
                            driverWithdraw.setMsg("");
                            baseMapper.updateById(driverWithdraw);
                        }
                    }
                }
            } else {
                String errMsg = MapUtil.getStr(result, "subMsg");
                if (ObjectUtil.isNotNull(id)) {
                    redisTemplate.delete("remitById:" + id);
                } else {
                    redisTemplate.delete("remitBatch");
                }
                String subCode = MapUtil.getStr(result, "subCode");
                if ("FB.BAL_NOT_ENOUGH".equals(subCode)) {
                    //获得指定日期是星期几，1表示周日，2表示周一
                    int i = DateUtil.dayOfWeek(DateUtil.date());
                    Boolean isWeekend = i == 1 || i == 7;
                    if (isWeekend) {
                        return RestResult.failed("节假日银行不结算,请节后等客服处理");
                    } else {
                        return RestResult.failed("收款行当前还未结算,请明天等待客服处理");
                    }

                }
                return RestResult.failed(errMsg);
            }

        }
        if (CollUtil.isNotEmpty(withdrawHistories)) {
            driverWithdrawHistoryService.saveBatch(withdrawHistories);
        }
        return RestResult.success();
    }

    @Override
    public RestResult remitHistory(Long id) {
        List<DriverWithdrawHistory> list = driverWithdrawHistoryService
                .list(Wrappers.<DriverWithdrawHistory>lambdaQuery()
                        .eq(DriverWithdrawHistory::getDriverWithdrawId, id)
                        .orderByAsc(DriverWithdrawHistory::getCreatedAt));
        return RestResult.success(list);
    }

    @Override
    public RestResult receiptFileDownload(Long id) {
        DriverWithdraw driverWithdraw = baseMapper.selectById(id);
        if (ObjectUtil.isNull(driverWithdraw)) {
            return RestResult.failed("提现记录不存在");
        }
        if (StrUtil.isBlank(driverWithdraw.getBankSerialNo())) {
            return RestResult.failed("交易还未完成,请稍等再试!");
        }
        String result = CmbPayClient.receiptFileDownload(driverWithdraw.getBankSerialNo());
        JSONObject jsonObject = JSON.parseObject(result);
        String code = jsonObject.getString("code");
        if (!"10000".equals(code)) {
            return RestResult.failed(jsonObject.getString("msg"));
        } else {
            String fileUrl = jsonObject.getJSONObject("data").getString("fileUrl");
            return RestResult.success(fileUrl);
        }
    }

    @Override
    public RestResult deleteById(Long id) {
        DriverWithdraw driverWithdraw = baseMapper.selectById(id);
        if (ObjectUtil.isNull(driverWithdraw)) {
            return RestResult.failed("删除失败,提现记录不存在");
        }
        if (DriverWithdrawState.done.equals(driverWithdraw.getState()) || DriverWithdrawState.operated.equals(driverWithdraw.getState())) {
            return RestResult.failed("删除失败,已完成或处理中的提现记录无法删除");
        }
        //删除记录
        baseMapper.deleteById(id);
        driverWithdrawHistoryService.remove(Wrappers.<DriverWithdrawHistory>lambdaQuery().eq(DriverWithdrawHistory::getDriverWithdrawId, id));
        //清除缓存
        primaryCachePutter.deleteDriverCacheById(driverWithdraw.getDriverId());


        DriverCustomMessage message = new DriverCustomMessage();
        message.setDriverId(driverWithdraw.getDriverId())
                .setContent("您于" + DateUtil.formatDateTime(driverWithdraw.getCreatedAt()) + "提现的" + driverWithdraw.getAmount() + "元由于提现信息有误已被退回,需要修改提现信息后重新提现")
                .setIsPlainText(true)
                .setLinkCategory(DriverCustomMessageLinkCategory.self)
                .setEventCategory(DriverCustomMessageEventCategory.system)
                .setIsRead(false);
        driverCustomMessageMapper.insert(message);
        return RestResult.success();
    }

    @Override
    public RestResult getAutoWithdrawAmount() {
        DriverWithDrawConfigMongo byDriverRegionId = driverWithDrawConfigRepository.findByDriverRegionId(0);
        return RestResult.success(ObjectUtil.isNotNull(byDriverRegionId) ? byDriverRegionId.getAmount() : "");
    }

    @Override
    public RestResult updateAutoWithdrawAmount(String amount) {
        DriverWithDrawConfigMongo byDriverRegionId = driverWithDrawConfigRepository.findByDriverRegionId(0);
        if (ObjectUtil.isNotNull(byDriverRegionId)) {
            Query query = new Query(Criteria.where("driverRegionId").is(0));
            Update update = new Update().set("amount", amount);
            mongoTemplate.updateFirst(query, update, DriverWithDrawConfigMongo.class);
        } else {
            DriverWithDrawConfigMongo add = new DriverWithDrawConfigMongo();
            add.setDriverRegionId(0).setIsActive(true).setAmount(new BigDecimal(amount)).setRemoteUrl("https://taxi-online.njydi.cn");
            driverWithDrawConfigRepository.save(add);
        }
        return RestResult.success();
    }

    @Override
    public List<Long> getDriverIds(List<Long> cans, List<Long> coms) {
        return driverMapper.queryDriverIdByList(cans, coms);
    }

    private DriverWithdrawHistory prepareHistoryData(DriverWithdraw driverWithdraw, DriverBanking banking, String bankCity, String failReason) {
        DriverWithdrawHistory driverWithdrawHistory = new DriverWithdrawHistory();
        driverWithdrawHistory.setDriverWithdrawId(driverWithdraw.getId());
        driverWithdrawHistory.setBatchNo(driverWithdraw.getBatchNo());
        driverWithdrawHistory.setSerialNo(driverWithdraw.getSerialNo());
        if (StrUtil.isNotBlank(failReason)) {
            driverWithdrawHistory.setFailReason(failReason);
            driverWithdrawHistory.setWithdrawFlag("F");
        } else {
            driverWithdrawHistory.setWithdrawFlag("W");
        }

        if (ObjectUtil.isNotNull(banking)) {
            driverWithdrawHistory.setBankName(banking.getBankName());
            driverWithdrawHistory.setCardNumber(banking.getCardNumber());
            driverWithdrawHistory.setNameOnCard(banking.getNameOnCard());
            if (StrUtil.isNotBlank(bankCity)) {
                driverWithdrawHistory.setBankCity(bankCity);
            }
            driverWithdrawHistory.setCreatedAt(DateUtil.date());
        }
        return driverWithdrawHistory;
    }

    private String getBatchNo() {
        String dateStr = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_PATTERN);
        String suffix = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        Set<String> remitBatchNos = redisTemplate.keys("remit_batchNo:" + dateStr + "*");
        if (CollUtil.isEmpty(remitBatchNos)) {
            String remit_batchNo = dateStr + "01A";
            redisTemplate.opsForValue().set("remit_batchNo:" + remit_batchNo, remit_batchNo, 24L, TimeUnit.HOURS);
            return remit_batchNo;
        } else {
            List<String> letterList = new ArrayList<>();
            remitBatchNos.forEach(set -> {
                String letter = set.substring(set.length() - 1, set.length());
                letterList.add(letter);
            });
            List<String> sortLetterList = letterList.stream().distinct().sorted().collect(Collectors.toList());
            String maxLetter = sortLetterList.get(sortLetterList.size() - 1);

            List<String> maxLetterBatchNos = new ArrayList<>();
            for (String maxLetterNo : remitBatchNos) {
                if (maxLetterNo.contains(maxLetter)) {
                    maxLetterBatchNos.add(maxLetterNo);
                }
            }
            List<Integer> ints = new ArrayList<>();
            System.out.println(maxLetterBatchNos);
            maxLetterBatchNos.forEach(set -> {
                String batch = set.substring(set.length() - 3, set.length() - 1);
                ints.add(Convert.toInt(batch));
            });
            Integer max = Collections.max(ints);
            String maxBatch = "";
            if (max < 99) {
                maxBatch = Convert.toStr(max + 1);
            } else {
                Integer maxLetterIndex = suffix.indexOf(maxLetter);
                maxLetter = suffix.substring(maxLetterIndex + 1, maxLetterIndex + 2);
                maxBatch = "001";
            }
            maxBatch = dateStr + (maxBatch.length() == 1 ? "0" + maxBatch : maxBatch) + maxLetter;
            redisTemplate.opsForValue().set("remit_batchNo:" + maxBatch, maxBatch, 24L, TimeUnit.HOURS);
            return maxBatch;
        }
    }
}
